<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>8. 错误和异常 &mdash; Python tutorial 3.4 documentation</title>
    
    <link rel="stylesheet" href="_static/default.css" type="text/css" />
    <link rel="stylesheet" href="_static/pygments.css" type="text/css" />
    
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    './',
        VERSION:     '3.4',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="_static/jquery.js"></script>
    <script type="text/javascript" src="_static/underscore.js"></script>
    <script type="text/javascript" src="_static/doctools.js"></script>
    <link rel="top" title="Python tutorial 3.4 documentation" href="index.html" />
    <link rel="next" title="9. 类" href="classes.html" />
    <link rel="prev" title="7. 输入和输出" href="inputoutput.html" /> 
  </head>
  <body>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             accesskey="I">index</a></li>
        <li class="right" >
          <a href="classes.html" title="9. 类"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="inputoutput.html" title="7. 输入和输出"
             accesskey="P">previous</a> |</li>
        <li><a href="index.html">Python tutorial 3.4 documentation</a> &raquo;</li> 
      </ul>
    </div>  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="tut-errors">
<span id="id1"></span><h1>8. 错误和异常<a class="headerlink" href="#tut-errors" title="Permalink to this headline">¶</a></h1>
<p>至今为止还没有进一步的谈论过错误信息，不过在你已经试验过的那些例子中，可能已经遇到过一些。Python 中（至少）有两种错误：语法错误和异常（ <em>syntax errors</em> 和 <em>exceptions</em> ）。</p>
<div class="section" id="tut-syntaxerrors">
<span id="id2"></span><h2>8.1. 语法错误<a class="headerlink" href="#tut-syntaxerrors" title="Permalink to this headline">¶</a></h2>
<p>语法错误，也被称作解析错误，也许是你学习 Python 过程中最常见抱怨:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="bp">True</span> <span class="k">print</span><span class="p">(</span><span class="s">&#39;Hello world&#39;</span><span class="p">)</span>
<span class="go">  File &quot;&lt;stdin&gt;&quot;, line 1, in ?</span>
<span class="go">    while True print(&#39;Hello world&#39;)</span>
<span class="go">                   ^</span>
<span class="go">SyntaxError: invalid syntax</span>
</pre></div>
</div>
<p>语法分析器指出错误行，并且在检测到错误的位置前面显示一个小“箭头”。 错误是由箭头 <em>前面</em> 的标记引起的（或者至少是这么检测的）： 这个例子中，函数 <tt class="xref py py-func docutils literal"><span class="pre">print()</span></tt> 被发现存在错误，因为它前面少了一个冒号（ <tt class="docutils literal"><span class="pre">':'</span></tt> ）。 错误会输出文件名和行号，所以如果是从脚本输入的你就知道去哪里检查错误了。</p>
</div>
<div class="section" id="tut-exceptions">
<span id="id3"></span><h2>8.2. 异常<a class="headerlink" href="#tut-exceptions" title="Permalink to this headline">¶</a></h2>
<p>即使一条语句或表达式在语法上是正确的，当试图执行它时也可能会引发错误。 运行期检测到的错误称为 <em>异常</em> ，并且程序不会无条件的崩溃：很快，你将学到如何在 Python 程序中处理它们。 然而，大多数异常都不会被程序处理，像这里展示的一样最终会产生一个错误信息:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="mi">10</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span><span class="o">/</span><span class="mi">0</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">?</span>
<span class="gr">ZeroDivisionError</span>: <span class="n">int division or modulo by zero</span>
<span class="gp">&gt;&gt;&gt; </span><span class="mi">4</span> <span class="o">+</span> <span class="n">spam</span><span class="o">*</span><span class="mi">3</span>
<span class="gt">Traceback (most recent call last):</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">?</span>
<span class="gr">NameError</span>: <span class="n">name &#39;spam&#39; is not defined</span>
<span class="gp">&gt;&gt;&gt; </span><span class="s">&#39;2&#39;</span> <span class="o">+</span> <span class="mi">2</span>
<span class="gt">Traceback (most recent call last):</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">?</span>
<span class="gr">TypeError</span>: <span class="n">Can&#39;t convert &#39;int&#39; object to str implicitly</span>
</pre></div>
</div>
<p>错误信息的最后一行指出发生了什么错误。异常也有不同的类型，异常类型做为错误信息的一部分显示出来：示例中的异常分别为 零除错误（ <tt class="xref py py-exc docutils literal"><span class="pre">ZeroDivisionError</span></tt> ） ，命名错误（ <tt class="xref py py-exc docutils literal"><span class="pre">NameError</span></tt>） 和 类型 错误（ <tt class="xref py py-exc docutils literal"><span class="pre">TypeError</span></tt> ）。打印错误信息时，异常的类型作为异常的内置名显示。对于所有的内置异常都是如此，不过用户自定义异常就不一定了（尽管这是一个很有用的约定）。标准异常名是内置的标识（没有保留关键字）。</p>
<p>这一行后一部分是关于该异常类型的详细说明，这意味着它的内容依赖于异常类型。</p>
<p>错误信息的前半部分以堆栈的形式列出异常发生的位置。通常在堆栈中列出了源代码行，然而，来自标准输入的源码不会显示出来。</p>
<p><em class="xref std std-ref">bltin-exceptions</em> 列出了内置异常和它们的含义。</p>
</div>
<div class="section" id="tut-handling">
<span id="id4"></span><h2>8.3. 异常处理<a class="headerlink" href="#tut-handling" title="Permalink to this headline">¶</a></h2>
<p>通过编程处理选择的异常是可行的。 看一下下面的例子：它会一直要求用户输入，直到输入一个合法的整数为止，但允许用户中断这个程序（使用 <tt class="kbd docutils literal"><span class="pre">Control-C</span></tt> 或系统支持的任何方法）。 注意：用户产生的中断会引发一个 <tt class="xref py py-exc docutils literal"><span class="pre">KeyboardInterrupt</span></tt> 异常。</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">while</span> <span class="bp">True</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
<span class="gp">... </span>        <span class="n">x</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="nb">input</span><span class="p">(</span><span class="s">&quot;Please enter a number: &quot;</span><span class="p">))</span>
<span class="gp">... </span>        <span class="k">break</span>
<span class="gp">... </span>    <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
<span class="gp">... </span>        <span class="k">print</span><span class="p">(</span><span class="s">&quot;Oops!  That was no valid number.  Try again...&quot;</span><span class="p">)</span>
<span class="gp">...</span>
</pre></div>
</div>
<p><tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 语句按如下方式工作。</p>
<ul class="simple">
<li>首先，执行 <em>try</em> 子句 （在 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 和 <tt class="xref std std-keyword docutils literal"><span class="pre">except</span></tt> 关键字之间的部分）。</li>
<li>如果没有异常发生， <em>except</em> 子句 在 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 语句执行完毕后就被忽略了。</li>
<li>如果在 try 子句执行过程中发生了异常，那么该子句其余的部分就会被忽略。如果异常匹配于 <tt class="xref std std-keyword docutils literal"><span class="pre">except</span></tt> 关键字后面指定的异常类型，就执行对应的except子句。然后继续执行 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 语句之后的代码。</li>
<li>如果发生了一个异常，在 <tt class="xref std std-keyword docutils literal"><span class="pre">except</span></tt> 子句中没有与之匹配的分支，它就会传递到上一级 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt>  语句中。如果最终仍找不到对应的处理语句，它就成为一个 <em>未处理异常</em> ，终止程序运行，显示提示信息。</li>
</ul>
<p>一个 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 语句可能包含多个 except 子句，分别指定处理不同的异常。至多只会有一个分支被执行。异常处理程序只会处理对应的 try 子句中发生的异常，在同一个 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt>  语句中，其他子句中发生的异常则不作处理。一个 except 子句可以在括号中列出多个异常的名字，例如:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="o">...</span> <span class="k">except</span> <span class="p">(</span><span class="ne">RuntimeError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="ne">NameError</span><span class="p">):</span>
<span class="o">...</span>     <span class="k">pass</span>
</pre></div>
</div>
<p>最后一个 except 子句可以省略异常名称，以作为通配符使用。 你需要慎用此法，因为它会轻易隐藏一个实际的程序错误！ 可以使用这种方法打印一条错误信息，然后重新抛出异常（允许调用者处理这个异常):</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">sys</span>

<span class="k">try</span><span class="p">:</span>
    <span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">&#39;myfile.txt&#39;</span><span class="p">)</span>
    <span class="n">s</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">readline</span><span class="p">()</span>
    <span class="n">i</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">s</span><span class="o">.</span><span class="n">strip</span><span class="p">())</span>
<span class="k">except</span> <span class="ne">IOError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">&quot;I/O error: {0}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">err</span><span class="p">))</span>
<span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">&quot;Could not convert data to an integer.&quot;</span><span class="p">)</span>
<span class="k">except</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">&quot;Unexpected error:&quot;</span><span class="p">,</span> <span class="n">sys</span><span class="o">.</span><span class="n">exc_info</span><span class="p">()[</span><span class="mi">0</span><span class="p">])</span>
    <span class="k">raise</span>
</pre></div>
</div>
<p><tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> ... <tt class="xref std std-keyword docutils literal"><span class="pre">except</span></tt> 语句可以带有一个 <em>else子句</em> ，该子句只能出现在所有 except 子句之后。当 try 语句没有抛出异常时，需要执行一些代码，可以使用这个子句。例如:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">arg</span> <span class="ow">in</span> <span class="n">sys</span><span class="o">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">:]:</span>
    <span class="k">try</span><span class="p">:</span>
        <span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="s">&#39;r&#39;</span><span class="p">)</span>
    <span class="k">except</span> <span class="ne">IOError</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="s">&#39;cannot open&#39;</span><span class="p">,</span> <span class="n">arg</span><span class="p">)</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="n">arg</span><span class="p">,</span> <span class="s">&#39;has&#39;</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()),</span> <span class="s">&#39;lines&#39;</span><span class="p">)</span>
        <span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
<p>使用 <tt class="xref std std-keyword docutils literal"><span class="pre">else</span></tt> 子句比在 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 子句中附加代码要好，因为这样可以避免 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> ... <tt class="xref std std-keyword docutils literal"><span class="pre">except</span></tt> 意外的截获本来不属于它们保护的那些代码抛出的异常。</p>
<p>发生异常时，可能会有一个附属值，作为异常的 <em>参数</em> 存在。这个参数是否存在、是什么类型，依赖于异常的类型。</p>
<p>在异常名（列表）之后，也可以为 except 子句指定一个变量。这个变量绑定于一个异常实例，它存储在 <tt class="docutils literal"><span class="pre">instance.args</span></tt> 的参数中。为了方便起见，异常实例定义了 <tt class="xref py py-meth docutils literal"><span class="pre">__str__()</span></tt>  ，这样就可以直接访问过打印参数而不必引用 <tt class="docutils literal"><span class="pre">.args</span></tt> 。 这种做法不受鼓励。相反，更好的做法是给异常传递一个参数（如果要传递多个参数，可以传递一个元组），把它绑定到 message 属性。一旦异常发生，它会在抛出前绑定所有指定的属性。</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span>   <span class="k">raise</span> <span class="ne">Exception</span><span class="p">(</span><span class="s">&#39;spam&#39;</span><span class="p">,</span> <span class="s">&#39;eggs&#39;</span><span class="p">)</span>
<span class="gp">... </span><span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">inst</span><span class="p">:</span>
<span class="gp">... </span>   <span class="k">print</span><span class="p">(</span><span class="nb">type</span><span class="p">(</span><span class="n">inst</span><span class="p">))</span>    <span class="c"># the exception instance</span>
<span class="gp">... </span>   <span class="k">print</span><span class="p">(</span><span class="n">inst</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>     <span class="c"># arguments stored in .args</span>
<span class="gp">... </span>   <span class="k">print</span><span class="p">(</span><span class="n">inst</span><span class="p">)</span>          <span class="c"># __str__ allows args to be printed directly,</span>
<span class="gp">... </span>                        <span class="c"># but may be overridden in exception subclasses</span>
<span class="gp">... </span>   <span class="n">x</span><span class="p">,</span> <span class="n">y</span> <span class="o">=</span> <span class="n">inst</span><span class="o">.</span><span class="n">args</span>     <span class="c"># unpack args</span>
<span class="gp">... </span>   <span class="k">print</span><span class="p">(</span><span class="s">&#39;x =&#39;</span><span class="p">,</span> <span class="n">x</span><span class="p">)</span>
<span class="gp">... </span>   <span class="k">print</span><span class="p">(</span><span class="s">&#39;y =&#39;</span><span class="p">,</span> <span class="n">y</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">&lt;class &#39;Exception&#39;&gt;</span>
<span class="go">(&#39;spam&#39;, &#39;eggs&#39;)</span>
<span class="go">(&#39;spam&#39;, &#39;eggs&#39;)</span>
<span class="go">x = spam</span>
<span class="go">y = eggs</span>
</pre></div>
</div>
<p>对于那些未处理的异常，如果一个它们带有参数，那么就会被作为异常信息的最后部分（“详情”）打印出来。</p>
<p>异常处理器不仅仅处理那些在 try 子句中立刻发生的异常，也会处理那些 try 子句中调用的函数内部发生的异常。 例如:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">this_fails</span><span class="p">():</span>
<span class="gp">... </span>    <span class="n">x</span> <span class="o">=</span> <span class="mi">1</span><span class="o">/</span><span class="mi">0</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span>    <span class="n">this_fails</span><span class="p">()</span>
<span class="gp">... </span><span class="k">except</span> <span class="ne">ZeroDivisionError</span> <span class="k">as</span> <span class="n">err</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">print</span><span class="p">(</span><span class="s">&#39;Handling run-time error:&#39;</span><span class="p">,</span> <span class="n">err</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">Handling run-time error: int division or modulo by zero</span>
</pre></div>
</div>
</div>
<div class="section" id="tut-raising">
<span id="id5"></span><h2>8.4. 抛出异常<a class="headerlink" href="#tut-raising" title="Permalink to this headline">¶</a></h2>
<p><tt class="xref std std-keyword docutils literal"><span class="pre">raise</span></tt> 语句允许程序员强制抛出一个指定的异常。例如:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">raise</span> <span class="ne">NameError</span><span class="p">(</span><span class="s">&#39;HiThere&#39;</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">?</span>
<span class="gr">NameError</span>: <span class="n">HiThere</span>
</pre></div>
</div>
<p>要抛出的异常由 <tt class="xref std std-keyword docutils literal"><span class="pre">raise</span></tt> 的唯一参数标识。它必需是一个异常实例或异常类（继承自 <tt class="xref py py-class docutils literal"><span class="pre">Exception</span></tt> 的类）。</p>
<p>如果你需要明确一个异常是否抛出，但不想处理它， <tt class="xref std std-keyword docutils literal"><span class="pre">raise</span></tt> 语句可以让你很简单的重新抛出该异常:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">raise</span> <span class="ne">NameError</span><span class="p">(</span><span class="s">&#39;HiThere&#39;</span><span class="p">)</span>
<span class="gp">... </span><span class="k">except</span> <span class="ne">NameError</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">print</span><span class="p">(</span><span class="s">&#39;An exception flew by!&#39;</span><span class="p">)</span>
<span class="gp">... </span>    <span class="k">raise</span>
<span class="gp">...</span>
<span class="go">An exception flew by!</span>
<span class="gt">Traceback (most recent call last):</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">2</span>, in <span class="n">?</span>
<span class="gr">NameError</span>: <span class="n">HiThere</span>
</pre></div>
</div>
</div>
<div class="section" id="tut-userexceptions">
<span id="id6"></span><h2>8.5. 用户自定义异常<a class="headerlink" href="#tut-userexceptions" title="Permalink to this headline">¶</a></h2>
<p>在程序中可以通过创建新的异常类型来命名自己的异常（Python 类的内容请参见 <a class="reference internal" href="classes.html#tut-classes"><em>类</em></a>  ）。异常类通常应该直接或间接的从 <tt class="xref py py-exc docutils literal"><span class="pre">Exception</span></tt> 类派生，例如:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">class</span> <span class="nc">MyError</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
<span class="gp">... </span>        <span class="bp">self</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="n">value</span>
<span class="gp">... </span>    <span class="k">def</span> <span class="nf">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="gp">... </span>        <span class="k">return</span> <span class="nb">repr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">raise</span> <span class="n">MyError</span><span class="p">(</span><span class="mi">2</span><span class="o">*</span><span class="mi">2</span><span class="p">)</span>
<span class="gp">... </span><span class="k">except</span> <span class="n">MyError</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">print</span><span class="p">(</span><span class="s">&#39;My exception occurred, value:&#39;</span><span class="p">,</span> <span class="n">e</span><span class="o">.</span><span class="n">value</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">My exception occurred, value: 4</span>
<span class="gp">&gt;&gt;&gt; </span><span class="k">raise</span> <span class="n">MyError</span><span class="p">(</span><span class="s">&#39;oops!&#39;</span><span class="p">)</span>
<span class="gt">Traceback (most recent call last):</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">?</span>
<span class="gr">__main__.MyError</span>: <span class="n">&#39;oops!&#39;</span>
</pre></div>
</div>
<p>在这个例子中，<tt class="xref py py-class docutils literal"><span class="pre">Exception</span></tt> 默认的 <tt class="xref py py-meth docutils literal"><span class="pre">__init__()</span></tt> 被覆盖。新的方式简单的创建 <em>value</em> 属性。这就替换了原来创建 <em>args</em> 属性的方式。</p>
<p>异常类中可以定义任何其它类中可以定义的东西，但是通常为了保持简单，只在其中加入几个属性信息，以供异常处理句柄提取。如果一个新创建的模块中需要抛出几种不同的错误时，一个通常的作法是为该模块定义一个异常基类，然后针对不同的错误类型派生出对应的异常子类:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Error</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Base class for exceptions in this module.&quot;&quot;&quot;</span>
    <span class="k">pass</span>

<span class="k">class</span> <span class="nc">InputError</span><span class="p">(</span><span class="n">Error</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Exception raised for errors in the input.</span>

<span class="sd">    Attributes:</span>
<span class="sd">        expression -- input expression in which the error occurred</span>
<span class="sd">        message -- explanation of the error</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">expression</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">expression</span> <span class="o">=</span> <span class="n">expression</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>

<span class="k">class</span> <span class="nc">TransitionError</span><span class="p">(</span><span class="n">Error</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Raised when an operation attempts a state transition that&#39;s not</span>
<span class="sd">    allowed.</span>

<span class="sd">    Attributes:</span>
<span class="sd">        previous -- state at beginning of transition</span>
<span class="sd">        next -- attempted new state</span>
<span class="sd">        message -- explanation of why the specific transition is not allowed</span>
<span class="sd">    &quot;&quot;&quot;</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">previous</span><span class="p">,</span> <span class="nb">next</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">previous</span> <span class="o">=</span> <span class="n">previous</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">next</span> <span class="o">=</span> <span class="nb">next</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span>
</pre></div>
</div>
<p>与标准异常相似，大多数异常的命名都以 “Error” 结尾。</p>
<p>很多标准模块中都定义了自己的异常，用以报告在他们所定义的函数中可能发生的错误。关于类的进一步信息请参见 <a class="reference internal" href="classes.html#tut-classes"><em>类</em></a> 一章。</p>
</div>
<div class="section" id="tut-cleanup">
<span id="id7"></span><h2>8.6. 定义清理行为<a class="headerlink" href="#tut-cleanup" title="Permalink to this headline">¶</a></h2>
<p><tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 语句还有另一个可选的子句，目的在于定义在任何情况下都一定要执行的功能。例如:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">try</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">raise</span> <span class="ne">KeyboardInterrupt</span>
<span class="gp">... </span><span class="k">finally</span><span class="p">:</span>
<span class="gp">... </span>    <span class="k">print</span><span class="p">(</span><span class="s">&#39;Goodbye, world!&#39;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="go">Goodbye, world!</span>
<span class="nc">KeyboardInterrupt</span>
</pre></div>
</div>
<p>不管有没有发生异常， <em>finally子句</em> 在程序离开 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 后都一定会被执行。当 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 语句中发生了未被 <tt class="xref std std-keyword docutils literal"><span class="pre">except</span></tt> 捕获的异常（或者它发生在 <tt class="xref std std-keyword docutils literal"><span class="pre">except</span></tt> 或 <tt class="xref std std-keyword docutils literal"><span class="pre">else</span></tt> 子句中），在 <tt class="xref std std-keyword docutils literal"><span class="pre">finally</span></tt> 子句执行完后它会被重新抛出。 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 语句经由 <tt class="xref std std-keyword docutils literal"><span class="pre">break</span></tt> ，<tt class="xref std std-keyword docutils literal"><span class="pre">continue</span></tt> 或 <tt class="xref std std-keyword docutils literal"><span class="pre">return</span></tt> 语句退 出也一样会执行 <tt class="xref std std-keyword docutils literal"><span class="pre">finally</span></tt> 子句。以下是一个更复杂些的例子（在同 一个 <tt class="xref std std-keyword docutils literal"><span class="pre">try</span></tt> 语句中的 <tt class="xref std std-keyword docutils literal"><span class="pre">except</span></tt> 和 <tt class="xref std std-keyword docutils literal"><span class="pre">finally</span></tt> 子句的工作方式与 Python 2.5 一样）:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="gp">&gt;&gt;&gt; </span><span class="k">def</span> <span class="nf">divide</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
<span class="gp">... </span>    <span class="k">try</span><span class="p">:</span>
<span class="gp">... </span>        <span class="n">result</span> <span class="o">=</span> <span class="n">x</span> <span class="o">/</span> <span class="n">y</span>
<span class="gp">... </span>    <span class="k">except</span> <span class="ne">ZeroDivisionError</span><span class="p">:</span>
<span class="gp">... </span>        <span class="k">print</span><span class="p">(</span><span class="s">&quot;division by zero!&quot;</span><span class="p">)</span>
<span class="gp">... </span>    <span class="k">else</span><span class="p">:</span>
<span class="gp">... </span>        <span class="k">print</span><span class="p">(</span><span class="s">&quot;result is&quot;</span><span class="p">,</span> <span class="n">result</span><span class="p">)</span>
<span class="gp">... </span>    <span class="k">finally</span><span class="p">:</span>
<span class="gp">... </span>        <span class="k">print</span><span class="p">(</span><span class="s">&quot;executing finally clause&quot;</span><span class="p">)</span>
<span class="gp">...</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="go">result is 2</span>
<span class="go">executing finally clause</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
<span class="go">division by zero!</span>
<span class="go">executing finally clause</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">divide</span><span class="p">(</span><span class="s">&quot;2&quot;</span><span class="p">,</span> <span class="s">&quot;1&quot;</span><span class="p">)</span>
<span class="go">executing finally clause</span>
<span class="gt">Traceback (most recent call last):</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">1</span>, in <span class="n">?</span>
  File <span class="nb">&quot;&lt;stdin&gt;&quot;</span>, line <span class="m">3</span>, in <span class="n">divide</span>
<span class="gr">TypeError: unsupported operand type(s) for /</span>: <span class="n">&#39;str&#39; and &#39;str&#39;</span>
</pre></div>
</div>
<p>如你所见， <tt class="xref std std-keyword docutils literal"><span class="pre">finally</span></tt> 子句在任何情况下都会执 行。 <tt class="xref py py-exc docutils literal"><span class="pre">TypeError</span></tt> 在两个字符串相除的时候抛出，未被 except 子句捕获，因此在 <tt class="xref std std-keyword docutils literal"><span class="pre">finally</span></tt> 子句执行完毕后重新抛出。</p>
<p>在真实场景的应用程序中， <tt class="xref std std-keyword docutils literal"><span class="pre">finally</span></tt> 子句用于释放外部资源（文件 或网络连接之类的），无论它们的使用过程中是否出错。</p>
</div>
<div class="section" id="tut-cleanup-with">
<span id="id8"></span><h2>8.7. 预定义清理行为<a class="headerlink" href="#tut-cleanup-with" title="Permalink to this headline">¶</a></h2>
<p>有些对象定义了标准的清理行为，无论对象操作是否成功，不再需要该对象的时 候就会起作用。以下示例尝试打开文件并把内容打印到屏幕上。</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="nb">open</span><span class="p">(</span><span class="s">&quot;myfile.txt&quot;</span><span class="p">):</span>
    <span class="k">print</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
</pre></div>
</div>
<p>这段代码的问题在于在代码执行完后没有立即关闭打开的文件。这在简单的脚本 里没什么，但是大型应用程序就会出问题。 <tt class="xref std std-keyword docutils literal"><span class="pre">with</span></tt> 语句使得文件之类的对象可以 确保总能及时准确地进行清理。</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">&quot;myfile.txt&quot;</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">f</span><span class="p">:</span>
        <span class="k">print</span><span class="p">(</span><span class="n">line</span><span class="p">)</span>
</pre></div>
</div>
<p>语句执行后，文件 <em>f</em> 总会被关闭，即使是在处理文件中的数据时出错也一样。 其它对象是否提供了预定义的清理行为要查看它们的文档。</p>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
  <h3><a href="index.html">Table Of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">8. 错误和异常</a><ul>
<li><a class="reference internal" href="#tut-syntaxerrors">8.1. 语法错误</a></li>
<li><a class="reference internal" href="#tut-exceptions">8.2. 异常</a></li>
<li><a class="reference internal" href="#tut-handling">8.3. 异常处理</a></li>
<li><a class="reference internal" href="#tut-raising">8.4. 抛出异常</a></li>
<li><a class="reference internal" href="#tut-userexceptions">8.5. 用户自定义异常</a></li>
<li><a class="reference internal" href="#tut-cleanup">8.6. 定义清理行为</a></li>
<li><a class="reference internal" href="#tut-cleanup-with">8.7. 预定义清理行为</a></li>
</ul>
</li>
</ul>

  <h4>Previous topic</h4>
  <p class="topless"><a href="inputoutput.html"
                        title="previous chapter">7. 输入和输出</a></p>
  <h4>Next topic</h4>
  <p class="topless"><a href="classes.html"
                        title="next chapter">9. 类</a></p>
  <h3>This Page</h3>
  <ul class="this-page-menu">
    <li><a href="_sources/errors.txt"
           rel="nofollow">Show Source</a></li>
  </ul>
<div id="searchbox" style="display: none">
  <h3>Quick search</h3>
    <form class="search" action="search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="Go" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    <p class="searchtip" style="font-size: 90%">
    Enter search terms or a module, class or function name.
    </p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related">
      <h3>Navigation</h3>
      <ul>
        <li class="right" style="margin-right: 10px">
          <a href="genindex.html" title="General Index"
             >index</a></li>
        <li class="right" >
          <a href="classes.html" title="9. 类"
             >next</a> |</li>
        <li class="right" >
          <a href="inputoutput.html" title="7. 输入和输出"
             >previous</a> |</li>
        <li><a href="index.html">Python tutorial 3.4 documentation</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer">
        &copy; Copyright 2013, D.D.
      Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.2.1.
    </div>
  </body>
</html>